package com.xbongbong.saas.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.PlatFormEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.menu.InitCrmMenuHelp;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.pojo.ButtonPojo;
import com.xbongbong.paas.pojo.DetaPhonePojo;
import com.xbongbong.paas.pojo.FieldAttrEntityForDecisionInfo;
import com.xbongbong.paas.pojo.SummaryDataPoJo;
import com.xbongbong.paas.pojo.dto.FormDataListDTO;
import com.xbongbong.paas.pojo.vo.PaasFormDataEsListVO;
import com.xbongbong.paas.service.CallCenterCommonService;
import com.xbongbong.paas.service.dynamic.crm.strategy.DecisionTreeDynamicStrategy;
import com.xbongbong.paas.service.dynamic.crm.strategy.DynamicStrategyFactory;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.parent.parse.data.FormDataListAnalysisDataHelp;
import com.xbongbong.pro.constant.CommonConstant;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.decisiontree.pojo.DecisionTreeLogDataPojo;
import com.xbongbong.pro.decisiontree.pojo.DecisionTreeLogPojo;
import com.xbongbong.pro.decisiontree.pojo.DecisionTreePojo;
import com.xbongbong.pro.decisiontree.pojo.dto.DecisionTreeGetDTO;
import com.xbongbong.pro.decisiontree.pojo.dto.DecisionTreeSaveDTO;
import com.xbongbong.pro.decisiontree.pojo.vo.DecisionTreeGetUpdateTimeVO;
import com.xbongbong.pro.decisiontree.pojo.vo.DecisionTreeGetVO;
import com.xbongbong.pro.decisiontree.pojo.vo.DecisionTreeSaveVO;
import com.xbongbong.pro.domain.entity.DecisionTreeEntity;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicDecisionTreeDTO;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.DecisionTreeErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.permission.enums.ProPermissionAliasEnum;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainDTO;
import com.xbongbong.pro.log.pojo.DetailLogComplexPojo;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.UserTeamEntity;
import com.xbongbong.saas.domain.entity.ext.ContactEntityExt;
import com.xbongbong.saas.enums.DecisionTreeContactTypeEnum;
import com.xbongbong.saas.enums.DetailTabEnum;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.PhoneExtEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContactEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.SalesOpportunityEnum;
import com.xbongbong.saas.help.DecisionTreeHelp;
import com.xbongbong.saas.help.SaasGetHelp;
import com.xbongbong.saas.help.SaasListHelp;
import com.xbongbong.saas.model.ContactModel;
import com.xbongbong.saas.model.DecisionTreeModel;
import com.xbongbong.saas.service.DecisionTreeService;
import com.xbongbong.saas.service.toolbox.help.LogHelp;
import com.xbongbong.saas.service.toolbox.help.UserTeamHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.model.UserModel;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * 决策树
 *
 * @Author: hongxiao
 * @date: 2021-11-20 10:49
 */
@Service("decisionTreeService")
public class DecisionTreeServiceImpl implements DecisionTreeService {
    private static final Logger LOG = LoggerFactory.getLogger(DecisionTreeServiceImpl.class);

    @Resource
    private DecisionTreeModel decisionTreeModel;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private SaasGetHelp saasGetHelp;
    @Resource
    private ContactModel contactModel;
    @Resource
    private CallCenterCommonService callCenterCommonService;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private UserTeamHelp userTeamHelp;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private LogHelp logHelp;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private FormDataListAnalysisDataHelp formDataListAnalysisDataHelp;
    @Resource
    private SaasListHelp saasListHelp;
    @Resource
    private InitCrmMenuHelp initCrmMenuHelp;
    @Resource
    private DecisionTreeHelp decisionTreeHelp;
    @Resource
    private UserModel userModel;
    @Resource
    private DynamicStrategyFactory dynamicStrategyFactory;

    @Override
    public DecisionTreeGetVO get(DecisionTreeGetDTO decisionTreeGetDTO) throws XbbException {
        DecisionTreeGetVO decisionTreeGetVO = new DecisionTreeGetVO();
        String corpid = decisionTreeGetDTO.getCorpid();
        String userId = decisionTreeGetDTO.getUserId();
        Integer businessType = decisionTreeGetDTO.getBusinessType();
        UserVO userVO = decisionTreeGetDTO.getLoginUser();

        // 获取联系人表单及表单解释
        Integer contactType = XbbRefTypeEnum.CONTACT.getCode();
        PaasFormEntityExt contactFormEntityExt = paasFormModel.getByBusinessType(contactType, corpid);
        Long contactFormId = contactFormEntityExt.getId();
        PaasFormExplainEntity contactFormExplain = paasFormExplainModel.getByFormId(contactFormId, corpid);
        List<FieldAttrEntity> contactExplainList = JSONArray.parseArray(contactFormExplain.getExplains(), FieldAttrEntity.class);
        Map<String, FieldAttrEntity> contactExplainMap = ExplainUtil.getExplainMap(contactFormExplain.getExplains(), null);

        //　机会返回项目决策信息解释
        List<String> closeAttrList =  new ArrayList<>();
        if (Objects.equals(XbbRefTypeEnum.SALES_OPPORTUNITY.getCode(), businessType)) {
            // 获取项目决策信息
            PaasFormEntityExt paasFormEntityExt = paasFormModel.getByBusinessType(XbbRefTypeEnum.PROJECT_DECISION_INFO.getCode(), corpid);
            if (Objects.isNull(paasFormEntityExt)) {
                initCrmMenuHelp.setDecisionInfoFormAndExplain(contactFormEntityExt.getAppId(), corpid, null);
                paasFormEntityExt = paasFormModel.getByBusinessType(XbbRefTypeEnum.PROJECT_DECISION_INFO.getCode(), corpid);
            }
            if (Objects.equals(paasFormEntityExt.getDel(), DelEnum.DELETE.getDel())) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_NOT_EXIST);
            }
            // 查看表单字段描述信息
            PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByFormId(paasFormEntityExt.getId(), corpid);

            if (Objects.isNull(paasFormExplainEntity) || Objects.equals(paasFormExplainEntity.getDel(),DelEnum.DELETE.getDel())) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
            }
            List<FieldAttrEntityForDecisionInfo> explainList =  JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntityForDecisionInfo.class);
            // 添加未启用的解释
            explainList.forEach(item -> {
                if (!Objects.equals(BasicConstant.ONE, item.getIsOpen())) {
                    closeAttrList.add(item.getAttr());
                }
            });
            // 过虑未启用解释
            explainList.removeIf(item -> !Objects.equals(BasicConstant.ONE, item.getIsOpen()));

            decisionTreeGetVO.setHeadList(explainList);
        }

        decisionTreeGetVO.setBusinessType(decisionTreeGetDTO.getBusinessType());
        decisionTreeGetVO.setFormId(decisionTreeGetDTO.getFormId());
        decisionTreeGetVO.setDataId(decisionTreeGetDTO.getDataId());
        decisionTreeGetVO.setContactExplainList(contactExplainList);

        try {

            // 获取客户id
            PaasFormDataEntityExt paasFormDataEntityExt = saasGetHelp.getFormData(decisionTreeGetDTO.getDataId(), corpid, businessType);
            if (Objects.isNull(paasFormDataEntityExt)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
            }
            Long customerId = decisionTreeGetDTO.getDataId();
            if (Objects.equals(XbbRefTypeEnum.SALES_OPPORTUNITY.getCode(), businessType)) {
                JSONObject data = paasFormDataEntityExt.getData();
                customerId = data.getLong(SalesOpportunityEnum.CUSTOMER_NAME.getAttr());
            }
            decisionTreeGetVO.setCustomerId(customerId);

            // 获取决策树信息
            DecisionTreeEntity decisionTreeEntity = decisionTreeModel.getByDataId(corpid, decisionTreeGetDTO.getBusinessType(), decisionTreeGetDTO.getFormId(), decisionTreeGetDTO.getDataId());
            if (Objects.nonNull(decisionTreeEntity)) {

                // 获取决策树中联系人信息，最多200个节点
                List<Long> contactIds = decisionTreeEntity.getContactIds().toJavaList(Long.class);
                List<Long> externalContactIds = decisionTreeEntity.getExternalContactIds().toJavaList(Long.class);
                List<Long> leftExternalContactIds = decisionTreeEntity.getLeftExternalContactIds().toJavaList(Long.class);
                Set<Long> allContactIds = new HashSet<>();
                allContactIds.addAll(contactIds);
                allContactIds.addAll(externalContactIds);
                // 去掉为null的值
                allContactIds.removeIf(Objects::isNull);

                // es查询数据
                IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_SAAS_CONTACT;
                BoolQueryBuilder boolQueryBuilder = boolQuery();
                boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD, corpid));
                boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
                boolQueryBuilder.filter(termsQuery(StringConstant.DATA_ID, allContactIds));
                boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
                SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
                // 搜索条件
                EsUtil.setPage(sourceBuilder, 1, allContactIds.size());
                sourceBuilder.query(boolQueryBuilder);
                //设置查询路由
                SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
                searchRequest.source(sourceBuilder);
                List<PaasFormDataEntityExt> contactList = xbbElasticsearchRestTemplate.queryForList(searchRequest, PaasFormDataEntityExt.class);

                // 创建人
                Map<Long, String> creatorMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                contactList.forEach(item -> {
                    creatorMap.put(item.getDataId(), item.getCreatorId());
                });

                PaasFormDataEsListVO paasFormDataEsListVO = new PaasFormDataEsListVO();
                paasFormDataEsListVO.setForm(contactFormEntityExt);
                paasFormDataEsListVO.setHeadList(contactExplainList);
                paasFormDataEsListVO.setPaasFormDataESList(contactList);

                saasListHelp.analysisSaasDataList(paasFormDataEsListVO, contactExplainMap);

                FormDataListDTO formDataListDTO = new FormDataListDTO();
                BeanUtil.copyProperties(decisionTreeGetDTO, formDataListDTO);
                formDataListDTO.setAppId(contactFormEntityExt.getAppId());
                formDataListDTO.setExplainMap(contactExplainMap);
                formDataListDTO.setBusinessType(contactType);
                formDataListDTO.setFieldList(null);
                formDataListDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
                formDataListDTO.setFormId(contactFormId);
                formDataListDTO.setDistributorMark(DistributorMarkEnum.OTHER.getCode());
                // web端逻辑，主要处理下关于关联数据，用户，部门数据回显的问题
                formDataListAnalysisDataHelp.analysisDataList(formDataListDTO, paasFormDataEsListVO);
                // 设置数据摘要和数据标签
                paasFormDataEsListVO = ExplainUtil.getValueByData(paasFormDataEsListVO, null, null);
                // 只存数据库未存es数据处理
                saasListHelp.setOnlyDBData(formDataListDTO, paasFormDataEsListVO);

                Map<Long, JSONObject> contactMap = new HashMap<>(contactList.size());
                List<Long> contactIdIn = new ArrayList<>();
                contactList.forEach(item -> {contactIdIn.add(item.getDataId());});

                //协同团队
                Map<Long, List<String>> mainUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<Long, List<String>> coUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                if (CollectionsUtil.isNotEmpty(contactIdIn)){
                    List<UserTeamEntity> userTeamList = userTeamHelp.getUserTeamList(contactIdIn, corpid, XbbRefTypeEnum.CONTACT.getCode(), false, null);
                    userTeamList.forEach(item -> {
                        if (Objects.equals(item.getIsMain(),BasicConstant.MAIN_USER)) {
                            List<String> teamUserIds = mainUserMap.getOrDefault(item.getDataId(), new ArrayList<>());
                            teamUserIds.add(item.getUserId());
                            mainUserMap.put(item.getDataId(), teamUserIds);
                        } else {
                            List<String> teamUserIds = coUserMap.getOrDefault(item.getDataId(), new ArrayList<>());
                            teamUserIds.add(item.getUserId());
                            coUserMap.put(item.getDataId(), teamUserIds);
                        }

                    });
                }
                Integer dataPermission = userModel.getDataPermission(userVO, false);
                List<String> userIdIn = userModel.getSubIdListByDataPermission(dataPermission, userId, corpid, BasicConstant.ZERO,false);
                // 当前数据的创建人、负责人、协同人、当前操作人
                HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();

                // saas权限
                boolean showContactPermission = userVO.getPermSet().contains(ProPermissionAliasEnum.CONTACT_VIEW.getAlias());
                boolean maxPermission = userVO.isAdminOrBoss() || userVO.isMaxDataPermission();
                for (PaasFormDataEntityExt contactEntityExt : paasFormDataEsListVO.getPaasFormDataESList()) {
                    Long dataId = contactEntityExt.getDataId();
                    // 团队成员
                    List<String> teamUserIds = new ArrayList<>();
                    teamUserIds.addAll(mainUserMap.getOrDefault(dataId, new ArrayList<>()));
                    teamUserIds.addAll(coUserMap.getOrDefault(dataId, new ArrayList<>()));
                    teamUserIds.removeIf(Objects::isNull);
                    String creatorId = creatorMap.get(dataId);
                    // 团队权限
                    boolean teamPermission = mainUserMap.getOrDefault(dataId, new ArrayList<>()).contains(userId) || coUserMap.getOrDefault(dataId, new ArrayList<>()).contains(userId);
                    // 数据权限
                    teamUserIds.retainAll(userIdIn);
                    boolean contactDataPermission = !teamUserIds.isEmpty();
                    // 超管、老板 || (联系人查看权限 && 数据权限) || 团队成员
                    boolean permissionFlag = maxPermission || (showContactPermission && contactDataPermission) || teamPermission;
                    JSONObject contactData = contactEntityExt.getData();


                    handlerExplainDTO.setLoginUser(userVO);
                    handlerExplainDTO.setOwnerId(mainUserMap.get(dataId));
                    handlerExplainDTO.setCoUserId(coUserMap.get(dataId));
                    handlerExplainDTO.setCreatorId(creatorId);
                    handlerExplainDTO.setUserId(userVO.getUserId());

                    // 联系人电话
                    JSONArray phoneJsonArray = contactData.getJSONArray(ContactEnum.PHONE.getAttr());
                    List<DetaPhonePojo> phonePojoList = new ArrayList<>();
                    if (CollectionsUtil.isNotEmpty(phoneJsonArray)) {
                        boolean attrVisible = commonHelp.attrCanSee(ContactEnum.PHONE.getAttr(), contactExplainMap, handlerExplainDTO);
                        boolean isShow = false;
                        if(permissionFlag && attrVisible){
                            List<? extends FieldAttrEntity> explainSubFormList = contactExplainMap.get(ContactEnum.PHONE.getAttr()).getSubForm().getItems();
                            Map<String, FieldAttrEntity> explainSubFormMap = new HashMap<>(explainSubFormList.size());
                            explainSubFormList.forEach((item) -> explainSubFormMap.put(item.getAttr(), item));
                            boolean text2CanSee = commonHelp.attrCanSee(StringConstant.PHONE_TEL_ATTR, explainSubFormMap, handlerExplainDTO);
                            if(text2CanSee){
                                isShow = true;
                            }
                        }
                        if (isShow) {
                            for (int i = 0; i < phoneJsonArray.size(); i++) {
                                String name = phoneJsonArray.getJSONObject(i).getString(StringConstant.PHONE_TYPE_ATTR);
                                String tel = phoneJsonArray.getJSONObject(i).getString(StringConstant.PHONE_TEL_ATTR);
                                DetaPhonePojo detaPhonePojo = new DetaPhonePojo();
                                detaPhonePojo.setName(PhoneExtEnum.getByCode(name).getName());
                                detaPhonePojo.setPhoneNum(tel);
                                detaPhonePojo.setTelNum(tel);
                                phonePojoList.add(detaPhonePojo);
                            }
                        }
                    }

                    // 回显的字段：头像、姓名、职位、电话，数据摘要（机会联系人）、数据标签（客户联系人）
                    // 姓名不做权限过虑，头像、职位、电话、数据摘要（机会联系人）、数据标签（客户联系人）做数据、表单权限过虑
                    boolean avatarCanSee = commonHelp.attrCanSee(ContactEnum.AVATAR.getAttr(), contactExplainMap, handlerExplainDTO);
                    boolean positionCanSee = commonHelp.attrCanSee(ContactEnum.POSITION.getAttr(), contactExplainMap, handlerExplainDTO);
                    // 详情标签、摘要(按顺序返回给前端)
                    List<SummaryDataPoJo> summaryList = decisionTreeHelp.summaryList(contactData, "summaryList", contactExplainMap, handlerExplainDTO, permissionFlag);
                    // 解析标签
                    List<SummaryDataPoJo> labelsList = decisionTreeHelp.summaryList(contactData, "labelsList", contactExplainMap, handlerExplainDTO, permissionFlag);
                    // 数据摘要，数据
                    JSONObject showData = new JSONObject();
                    showData.put(ContactEnum.NAME.getAttr(), contactData.getOrDefault(ContactEnum.NAME.getAttr(), ""));
                    showData.put(ContactEnum.AVATAR.getAttr(), decisionTreeHelp.handleAttrCanSee(ContactEnum.AVATAR.getAttr(), contactData, avatarCanSee && permissionFlag));
                    showData.put(ContactEnum.POSITION.getAttr(), decisionTreeHelp.handleAttrCanSee(ContactEnum.POSITION.getAttr(), contactData, positionCanSee && permissionFlag));
                    showData.put("phone", phonePojoList);
                    showData.put("summaryList", summaryList);
                    showData.put("labelsList", labelsList);

                    contactMap.put(contactEntityExt.getDataId(), showData);
                }

                decisionTreeGetVO.setId(decisionTreeEntity.getId());
                contactIds.retainAll(contactIdIn);
                externalContactIds.retainAll(contactIdIn);
                decisionTreeGetVO.setContactIds(contactIds);
                decisionTreeGetVO.setExternalContactIds(externalContactIds);
                // 左侧外部联系人ids
                decisionTreeGetVO.setLeftExternalContactIds(leftExternalContactIds);

                //　处理节点
                int keySetCount = Objects.nonNull(decisionTreeEntity.getNodeData()) ? decisionTreeEntity.getNodeData().keySet().size() :  BasicConstant.ZERO;
                DecisionTreePojo rootNode = (keySetCount > BasicConstant.ZERO) ? decisionTreeEntity.getNodeData().toJavaObject(DecisionTreePojo.class) : null;
                List<DecisionTreePojo> decisionTree = new ArrayList<>();
                if (Objects.nonNull(rootNode)) {
                    setNodeData(rootNode, contactMap, closeAttrList, externalContactIds);
                    decisionTree.add(rootNode);
                }
                decisionTreeGetVO.setDecisionTree(decisionTree);
            }

            // 权限：编辑、添加联系人、呼叫座席、云呼座席
            List<ButtonPojo> permissions = getPermissions(corpid, userId, userVO, businessType);
            decisionTreeGetVO.setPermissions(permissions);

        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("decisionTreeService.get报错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }

        return decisionTreeGetVO;
    }

    @Override
    public DecisionTreeGetUpdateTimeVO getUpdateTime(DecisionTreeGetDTO decisionTreeGetDTO) throws XbbException {
        DecisionTreeGetUpdateTimeVO decisionTreeGetUpdateTimeVO = new DecisionTreeGetUpdateTimeVO();

        Long lastUpdateTime = BasicConstant.ZERO_LONG;
        DecisionTreeEntity decisionTreeEntity = decisionTreeModel.getByDataId(decisionTreeGetDTO.getCorpid(), decisionTreeGetDTO.getBusinessType(), decisionTreeGetDTO.getFormId(), decisionTreeGetDTO.getDataId());
        if (Objects.nonNull(decisionTreeEntity)) {
            lastUpdateTime = decisionTreeEntity.getUpdateTime();
        }

        decisionTreeGetUpdateTimeVO.setBusinessType(decisionTreeGetDTO.getBusinessType());
        decisionTreeGetUpdateTimeVO.setFormId(decisionTreeGetDTO.getFormId());
        decisionTreeGetUpdateTimeVO.setDataId(decisionTreeGetDTO.getDataId());
        decisionTreeGetUpdateTimeVO.setLastUpdateTime(lastUpdateTime);

        return decisionTreeGetUpdateTimeVO;
    }

    @Override
    public DecisionTreeSaveVO save(DecisionTreeSaveDTO decisionTreeSaveDTO) throws XbbException {
        DecisionTreeSaveVO decisionTreeSaveVO = new DecisionTreeSaveVO();

        String corpid = decisionTreeSaveDTO.getCorpid();
        String userId = decisionTreeSaveDTO.getUserId();
        Integer businessType = decisionTreeSaveDTO.getBusinessType();

        Long dataId = decisionTreeSaveDTO.getDataId();
        UserVO userVO = decisionTreeSaveDTO.getLoginUser();
        List<DecisionTreePojo> decisionTreePojoList = decisionTreeSaveDTO.getDecisionTree();
        DecisionTreeLogPojo logData = decisionTreeSaveDTO.getLogData();
        Long lastUpdateTime = Objects.isNull(decisionTreeSaveDTO.getLastUpdateTime()) ? BasicConstant.ZERO_LONG : decisionTreeSaveDTO.getLastUpdateTime();

        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(businessType);
        boolean isOpportunity = XbbRefTypeEnum.SALES_OPPORTUNITY == xbbRefTypeEnum;

        // 判断权限
        String editPermissionName = isOpportunity ?
                ProPermissionAliasEnum.CONTACT_DECISION_TREE_EDIT.getMemo() : ProPermissionAliasEnum.CONTACT_ORGANIZATION_TREE_EDIT.getMemo();
        if (!hasEditPermission(businessType, userVO)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100050, String.format(SystemErrorCodeEnum.API_ERROR_100050.getMsg(), editPermissionName));
        }
        // 获取业务数据
        PaasFormDataEntityExt paasFormDataEntityExt = saasGetHelp.getFormData(dataId, corpid, businessType);
        if (Objects.isNull(paasFormDataEntityExt)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
        }
        Long formId = paasFormDataEntityExt.getFormId();
        DecisionTreeEntity oldEntity = decisionTreeModel.getByDataId(corpid, businessType, formId, dataId);
        DecisionTreeEntity decisionTreeEntity = new DecisionTreeEntity();
        boolean isNew = false;
        Long dbUpdateTime = BasicConstant.ZERO_LONG;
        if (Objects.isNull(oldEntity)) {
            isNew = true;
            oldEntity = new DecisionTreeEntity();
            oldEntity.setCorpid(corpid);
            oldEntity.setBusinessType(businessType);
            oldEntity.setFormId(formId);
            oldEntity.setDataId(dataId);
            oldEntity.setAppId(paasFormDataEntityExt.getAppId());
            oldEntity.setMenuId(paasFormDataEntityExt.getMenuId());
            oldEntity.setSaasMark(SaasMarkEnum.SAAS.getCode());
            oldEntity.setCreatorId(userId);
        } else {
            dbUpdateTime = oldEntity.getUpdateTime();
        }
        // 前端传入更新时间与数据更新时间比较
        if (!Objects.equals(dbUpdateTime, lastUpdateTime)) {
            decisionTreeSaveVO.setHasModify(BasicConstant.ONE);
            return decisionTreeSaveVO;
        }
        // 无操作日志不做修改
        if (Objects.isNull(logData)) {
            return decisionTreeSaveVO;
        }

        boolean needUpdateFlag = CollectionsUtil.isNotEmpty(logData.getAddNodes()) || CollectionsUtil.isNotEmpty(logData.getDeleteNodes());
        // 操作日志只有编辑节点数据，且编辑前和编辑后内容一致，不做修改
        if (CollectionsUtil.isNotEmpty(logData.getUpdateNodes())) {
            for (DecisionTreeLogDataPojo logDataPojo : logData.getUpdateNodes()) {
                needUpdateFlag = logHelp.checkDecisionTreeNodeUpdate(logDataPojo);
                if (needUpdateFlag) {
                    break;
                }
            }
        }

        // 只修改了左侧外部联系保存
        if (!needUpdateFlag) {
            onlyLeftExternalContact(oldEntity, decisionTreeSaveDTO.getLeftExternalContactIds(), decisionTreeSaveDTO.getPlatform(), xbbRefTypeEnum);
            return decisionTreeSaveVO;
        }

        JSONObject data = paasFormDataEntityExt.getData();
        Long customerId = dataId;
        String dataName;
        if (isOpportunity) {
            customerId = data.getLong(SalesOpportunityEnum.CUSTOMER_NAME.getAttr());
            // 机会：编号＋名称
            String serialNo = paasFormDataEntityExt.getSerialNo();
            StringBuilder sb = new StringBuilder();
            dataName = FastJsonHelper.getStringOrDefaultFromFormData(paasFormDataEntityExt.getData(), SalesOpportunityEnum.NAME.getAttr(), "");
            dataName = StringUtil.isEmpty(dataName) ? serialNo : sb.append(serialNo).append("（").append(dataName).append("）").toString();
        } else {
            // 客户：名称
            dataName = data.getString(CustomerManagementEnum.NAME.getAttr());
        }

        // 判断决策树节点数量和层级
        DecisionTreePojo rootDecisionTreePojo = CollectionsUtil.isEmpty(decisionTreePojoList) ? null : decisionTreePojoList.get(0);
        checkNode(rootDecisionTreePojo);
        List<Long> allNodeContactIds = new ArrayList<>();
        List<Long> contactIds = new ArrayList<>();
        getAllContactIds(rootDecisionTreePojo, allNodeContactIds);
        // 去掉联系人信息
        removeContactInfo(rootDecisionTreePojo);
        // 获取日志中的联系人
        List<Long> contactIds4Log = new ArrayList<>();
        contactIds4Log.addAll(getContactIds4Log(logData.getAddNodes()));
        contactIds4Log.addAll(getContactIds4Log(logData.getDeleteNodes()));
        contactIds4Log.addAll(getContactIds4Log(logData.getUpdateNodes()));
        Set<Long> allContactSet = new HashSet<>(allNodeContactIds);
        allContactSet.addAll(contactIds4Log);
        // 去掉为null的值
        allContactSet.removeIf(Objects::isNull);
        Map<Long, String> contactNameMap = new HashMap<>();

        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(StringConstant.CORPID, corpid);
        param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
        param.put(StringConstant.IDIN, allContactSet);
        List<ContactEntityExt> contactList = contactModel.findEntitysWithoutSub(param);
        for (ContactEntityExt contactEntityExt : contactList) {
            JSONObject contactData = contactEntityExt.getData();
            String name = contactData.getString(ContactEnum.NAME.getAttr());
            contactNameMap.put(contactEntityExt.getDataId(), name);
            Long linkCustomerId = contactData.getLong(ContactEnum.CUSTOMER_NAME.getAttr());
            if (Objects.equals(customerId, linkCustomerId)) {
                contactIds.add(contactEntityExt.getDataId());
            }
        }
        // 去掉为null的值
        contactIds.removeIf(Objects::isNull);
        // 获取内部联系人
        contactIds.retainAll(allNodeContactIds);
        // 获取外部联系人id
        allNodeContactIds.removeAll(contactIds);
        if (allNodeContactIds.size() > BasicConstant.TWENTY) {
            throw new XbbException(DecisionTreeErrorCodeEnum.API_ERROR_1510003);
        }
        List<Long> externalContactIds = new ArrayList<>(allNodeContactIds);
        // 去掉为null的值
        externalContactIds.removeIf(Objects::isNull);
        try {

            BeanUtil.copyProperties(oldEntity, decisionTreeEntity);
            JSONArray contactData = new JSONArray();
            if (CollectionsUtil.isNotEmpty(contactIds)) {
                contactData.addAll(contactIds);
            }
            JSONArray externalContactData = new JSONArray();
            if (CollectionsUtil.isNotEmpty(externalContactIds)) {
                externalContactData.addAll(externalContactIds);
            }
            // 左侧外部联系人
            if (Objects.equals(PlatFormEnum.WEB.getValue(), decisionTreeSaveDTO.getPlatform())) {
                List<Long> leftExternalContactIds = decisionTreeSaveDTO.getLeftExternalContactIds();
                // 左侧外部联系人不能超过200个
                if (CollectionsUtil.isNotEmpty(leftExternalContactIds) && leftExternalContactIds.size() > BasicConstant.TWO_HUNDRED) {
                    throw new XbbException(DecisionTreeErrorCodeEnum.API_ERROR_1510004);
                }
                leftExternalContactIds.removeIf(Objects::isNull);
                JSONArray leftExternalContactData = new JSONArray();
                leftExternalContactData.addAll(leftExternalContactIds);
                decisionTreeEntity.setLeftExternalContactIds(leftExternalContactData);
            }
            // 左侧外部联系人ids
            if (Objects.isNull(decisionTreeEntity.getLeftExternalContactIds())) {
                decisionTreeEntity.setLeftExternalContactIds(new JSONArray());
            }
            JSONObject nodeData = Objects.nonNull(rootDecisionTreePojo) ? JSON.parseObject(JSONObject.toJSON(rootDecisionTreePojo).toString()) : new JSONObject();
            decisionTreeEntity.setNodeData(nodeData);
            decisionTreeEntity.setContactIds(contactData);
            decisionTreeEntity.setExternalContactIds(externalContactData);

            decisionTreeModel.save(decisionTreeEntity);
            List<Long> dbContactIds = decisionTreeEntity.getContactIds().toJavaList(Long.class);
            List<Long> dbExternalContactIds = decisionTreeEntity.getExternalContactIds().toJavaList(Long.class);
            List<Long> dbLeftExternalContactIds = decisionTreeEntity.getLeftExternalContactIds().toJavaList(Long.class);
            decisionTreeSaveVO.setContactIds(dbContactIds);
            decisionTreeSaveVO.setExternalContactIds(dbExternalContactIds);
            decisionTreeSaveVO.setLeftExternalContactIds(dbLeftExternalContactIds);

            // 日志
            OperateModuleTypeEnum operateModuleTypeEnum = isOpportunity ? OperateModuleTypeEnum.OPPORTUNITY : OperateModuleTypeEnum.CUSTOMER;
            OperateTypeEnum  operateTypeEnum = isNew ? OperateTypeEnum.NEW : OperateTypeEnum.EDIT;
            String opObjectName = isOpportunity ? I18nMessageUtil.getMessage(DetailTabEnum.SALES_OPPORTUNITY_CONTACT.getName()) : I18nMessageUtil.getMessage(DetailTabEnum.CONTACT_ORGANIZATION_TREE.getName());
            String opUserName = userVO.getName();
            String memo;
            if (isNew) {
                memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_DECISION_TREE_ADD), opUserName, xbbRefTypeEnum.getName(), dataName, opObjectName);
                mongoLogHelp.saveLoggerByInsert(corpid, userId, opUserName, opObjectName, memo, decisionTreeEntity.getId().toString(), decisionTreeSaveDTO.getHttpHeader(), operateModuleTypeEnum, operateTypeEnum);
            } else {
                Map<String, String> explainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                if (isOpportunity) {
                    // 获取项目决策信息
                    PaasFormEntityExt paasFormEntityExt = paasFormModel.getByBusinessType(XbbRefTypeEnum.PROJECT_DECISION_INFO.getCode(), corpid);
                    // 查看表单字段描述信息
                    PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByFormId(paasFormEntityExt.getId(), corpid);
                    List<FieldAttrEntityForDecisionInfo> explainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntityForDecisionInfo.class);
                    explainList.forEach(item -> {
                        explainMap.put(item.getAttr(), item.getAttrName());
                    });
                }
                // 旧空树：新增；新空树：删除
                int keySetCount = oldEntity.getNodeData().keySet().size();
                if (keySetCount == 0) {
                    // 新增
                    memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_DECISION_TREE_ADD), opUserName, xbbRefTypeEnum.getName(), dataName, opObjectName);
                    mongoLogHelp.saveLoggerByInsert(corpid, userId, opUserName, opObjectName, memo, decisionTreeEntity.getId().toString(), decisionTreeSaveDTO.getHttpHeader(), operateModuleTypeEnum, operateTypeEnum);
                } else if (Objects.isNull(rootDecisionTreePojo)) {
                    //删除
                    memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_DECISION_TREE_DELETE), opUserName, xbbRefTypeEnum.getName(), dataName, opObjectName);
                    mongoLogHelp.saveLoggerByInsert(corpid, userId, opUserName, opObjectName, memo, decisionTreeEntity.getId().toString(), decisionTreeSaveDTO.getHttpHeader(), operateModuleTypeEnum, operateTypeEnum);
                } else {
                    // 添加占位联系人到在map中，日志使用
                    contactNameMap.put(BasicConstant.ZERO_LONG, I18nMessageUtil.getMessage(CommonConstant.PLACEHOLDER_CONTACT));
                    memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_DECISION_TREE_UPDATE), opUserName, xbbRefTypeEnum.getName(), dataName, opObjectName);
                    List<DetailLogComplexPojo> detailArr = logHelp.detailLog4DecisionTree(contactNameMap, explainMap, logData);
                    mongoLogHelp.buildLog4ComplexDetailArr(detailArr, corpid, userId, opUserName, operateModuleTypeEnum, operateTypeEnum, decisionTreeEntity.getId().toString(), opObjectName, memo, decisionTreeSaveDTO.getHttpHeader());
                }
            }
            // 加动态

            DecisionTreeDynamicStrategy decisionTreeDynamicStrategy =
                    dynamicStrategyFactory.getDecisionTreeDynamicStrategy(businessType);
            DynamicDecisionTreeDTO dynamicPushNotifyAddDTO = new DynamicDecisionTreeDTO();
            dynamicPushNotifyAddDTO.setDecisionTreeSaveDTO(decisionTreeSaveDTO);
            dynamicPushNotifyAddDTO.setNew(isNew);
            decisionTreeDynamicStrategy.addOrDelete(dynamicPushNotifyAddDTO);



        } catch (XbbException e) {
            LOG.error("保存决策树失败~~~", e);
            throw e;
        } catch (Exception e) {
            LOG.error("保存决策树失败!!!", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }

        return decisionTreeSaveVO;
    }

    /***
     * 添加节点联系人信息
     *
     * @param node 节点
     * @param: contactMap 联系人map
     * @throws
     * @return void
     * @author hongxiao
     * @date 2021-11-22 10:00
     * @since
     * @version
     */
    private void setNodeData(DecisionTreePojo node, Map<Long, JSONObject> contactMap, List<String> closeAttrList, List<Long> externalContactIds) {
        JSONObject contactData = contactMap.get(node.getContactId());
        JSONObject info = node.getInfo();
        if (Objects.nonNull(info) && CollectionsUtil.isNotEmpty(closeAttrList)) {
            closeAttrList.forEach(info::fluentRemove);
        }
        // 外部联系人
        int externalFlag = CollectionsUtil.isNotEmpty(externalContactIds) && externalContactIds.contains(node.getContactId()) ? BasicConstant.ONE : BasicConstant.ZERO;
        node.setExternalContactFlag(externalFlag);
        // 判断节点联系人类型
        if (Objects.nonNull(contactData)) {
            // 添加联系人数据
            node.setContact(contactData);
            node.setContactType(DecisionTreeContactTypeEnum.NORMAL_CONTACT.getCode());
        } else if (Objects.equals(node.getContactId(), BasicConstant.ZERO_LONG)) {
            // 占位联系人
            node.setContactType(DecisionTreeContactTypeEnum.PLACEHOLDER_CONTACT.getCode());
        } else {
            // 联系人被删除
            node.setContactType(DecisionTreeContactTypeEnum.DELETE_CONTACT.getCode());
        }
        List<DecisionTreePojo> childList = node.getChildren();
        if (CollectionsUtil.isNotEmpty(childList)) {
            for (DecisionTreePojo treePojo : childList) {
                setNodeData(treePojo, contactMap, closeAttrList, externalContactIds);
            }
        }
    }

    /***
     * 获取节点中的联系人ids
     *
     * @param node
     * @param: contactIds
     * @throws
     * @return void
     * @author hongxiao
     * @date 2021-12-18 16:46
     * @since
     * @version
     */
    private void getAllContactIds(DecisionTreePojo node, List<Long> contactIds) throws XbbException {
        if (Objects.isNull(node)) {
            return;
        }
        Long contactId = node.getContactId();
        if (!Objects.equals(BasicConstant.ZERO_LONG, contactId)) {
            if (contactIds.contains(contactId)) {
                throw new XbbException(DecisionTreeErrorCodeEnum.API_ERROR_1510005);
            }
            contactIds.add(contactId);
        }
        List<DecisionTreePojo> childList = node.getChildren();
        if (CollectionsUtil.isNotEmpty(childList)) {
            for (DecisionTreePojo treePojo : childList) {
                getAllContactIds(treePojo, contactIds);
            }
        }
    }

    /***
     * 删除节点联系人信息
     *
     * @param node
     * @throws
     * @return void
     * @author hongxiao
     * @date 2022-02-21 19:19
     * @since
     * @version
     */
    private void removeContactInfo(DecisionTreePojo node) {
        if (Objects.isNull(node)) {
            return;
        }
        node.setContact(null);
        List<DecisionTreePojo> childList = node.getChildren();
        if (CollectionsUtil.isNotEmpty(childList)) {
            for (DecisionTreePojo treePojo : childList) {
                removeContactInfo(treePojo);
            }
        }
    }

    /***
     * 获取操作日志中联系人ids
     *
     * @param nodes 日志节点
     * @throws
     * @return java.util.List<java.lang.Long>
     * @author hongxiao
     * @date 2021-12-18 17:25
     * @since
     * @version
     */
    private List<Long> getContactIds4Log(List<DecisionTreeLogDataPojo> nodes) {

        if (CollectionsUtil.isEmpty(nodes)) {
            return new ArrayList<>();
        }
        Set<Long> contactIds = new HashSet<>();
        for (DecisionTreeLogDataPojo logPojo : nodes) {
            contactIds.add(logPojo.getParentContactId());
            contactIds.add(logPojo.getContactId());
            contactIds.add(logPojo.getOldParentContactId());
            contactIds.add(logPojo.getOldContactId());
        }
        // 去掉占位联系人
        contactIds.remove(BasicConstant.ZERO_LONG);
        return new ArrayList<>(contactIds);
    }

    /***
     * 校验节点数量和深度
     *
     * @param node 节点
     * @throws
     * @return void
     * @author hongxiao
     * @date 2021-11-22 10:01
     * @since
     * @version
     */
    private void checkNode(DecisionTreePojo node) throws XbbException {
        Map<String, Integer> treeCountAndDepthMap = new HashMap<>(PaasConstant.DEFAULT_ACCURACY);
        treeCountAndDepth(node, treeCountAndDepthMap);
        Integer count = treeCountAndDepthMap.get("count");
        Integer depth = treeCountAndDepthMap.get("depth");
        if (count > BasicConstant.TWO_HUNDRED) {
            throw new XbbException(DecisionTreeErrorCodeEnum.API_ERROR_1510001);
        }
        if (depth > BasicConstant.TWENTY) {
            throw new XbbException(DecisionTreeErrorCodeEnum.API_ERROR_1510002);
        }
    }

    /**
     * 获取节点数量和深度
     *
     * @param node
     * @param: treeCountAndDepthMap
     * @throws
     * @return void
     * @author hongxiao
     * @date 2021-11-22 10:02
     * @since
     * @version
     */
    private void treeCountAndDepth(DecisionTreePojo node, Map<String, Integer> treeCountAndDepthMap) {
        if (Objects.isNull(node)) {
            treeCountAndDepthMap.put("count", 0);
            treeCountAndDepthMap.put("depth", 0);
            return;
        }
        LinkedList<DecisionTreePojo> list = new LinkedList<>();
        list.add(node);
        int depth = 0, curCount = 0, nextCount = list.size(), allCount = 0;
        while (CollectionsUtil.isNotEmpty(list)) {
            DecisionTreePojo curNode = list.pop();
            curCount ++;
            allCount ++;
            List<DecisionTreePojo> childList = curNode.getChildren();
            if (CollectionsUtil.isNotEmpty(childList)) {
                list.addAll(childList);
            }
            if (curCount == nextCount) {
                curCount = 0;
                nextCount = list.size();
                depth++;
            }
        }
        treeCountAndDepthMap.put("count", allCount);
        treeCountAndDepthMap.put("depth", depth);
    }

    /***
     * 获取决策树相关权限
     * 
     * @param corpid 公司id
     * @param: userId 员工id
     * @param: userVO 员工vo
     * @param: businessType 业务类型
     * @throws 
     * @return List<ButtonPojo>
     * @author hongxiao
     * @date 2021-11-25 15:50
     * @since
     * @version
     */
    private List<ButtonPojo> getPermissions(String corpid, String userId, UserVO userVO, Integer businessType) {
        List<ButtonPojo> permissions = new ArrayList<>();
        // 客户或机会的决策树编辑权限
        boolean edit = hasEditPermission(businessType, userVO);
        boolean addContact = userVO.getPermSet().contains(ProPermissionAliasEnum.CONTACT_ADD.getAlias());
        // 判断是否有呼叫权限
        boolean isActiveCall;
        try {
            isActiveCall = callCenterCommonService.isOpenCallAndAgent(corpid, userId);
        } catch (XbbException e) {
            isActiveCall = false;
        }
        // 判断是否有阿里云呼叫中心权限
        boolean isActiveAliyunCall;
        try {
            isActiveAliyunCall = callCenterCommonService.isActiveAliyunCall(corpid, userId).IsActiveAliyunAndHasRole();
        } catch (XbbException e) {
            isActiveAliyunCall = false;
        }
        if (edit) {
            ButtonPojo buttonPojo = new ButtonPojo();
            buttonPojo.setAttr("edit");
            buttonPojo.setValue("编辑");
            permissions.add(buttonPojo);
        }
        if (addContact) {
            ButtonPojo buttonPojo = new ButtonPojo();
            buttonPojo.setAttr("addContact");
            buttonPojo.setValue("更多联系人");
            permissions.add(buttonPojo);
        }
        if (isActiveCall) {
            ButtonPojo buttonPojo = new ButtonPojo();
            buttonPojo.setAttr("activeCall");
            buttonPojo.setValue("呼叫中心权限");
            permissions.add(buttonPojo);
        }
        if (isActiveAliyunCall) {
            ButtonPojo buttonPojo = new ButtonPojo();
            buttonPojo.setAttr("activeAliyunCall");
            buttonPojo.setValue("云呼权限");
            permissions.add(buttonPojo);
        }
        return permissions;
    }

    /***
     * 是否有权限
     *
     * @param businessType 业务类型
     * @param: permissions 权限列表
     * @throws
     * @return boolean
     * @author hongxiao
     * @date 2021-11-25 15:53
     * @since
     * @version
     */
    private boolean hasEditPermission(Integer businessType, UserVO userVO) {
        if (userVO.isAdminOrBoss()) {
            return true;
        }
        Set<String> permissions = userVO.getPermSet();
        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(businessType);
        boolean flag;
        switch (xbbRefTypeEnum) {
            case CUSTOMER_MANAGEMENT:
                flag = permissions.contains(ProPermissionAliasEnum.CONTACT_ORGANIZATION_TREE_EDIT.getAlias());
                break;
            case SALES_OPPORTUNITY:
                flag = permissions.contains(ProPermissionAliasEnum.CONTACT_DECISION_TREE_EDIT.getAlias());
                break;
            default:
                flag = false;
                break;
        }
        return flag;
    }

    /**
     * 无改动决策树节点，只修改了外部联系人
     * @param entity 决策树实体
     * @param contactIds 外部联系人
     * @param platform 平台
     * @param xbbRefTypeEnum 业务类型
     * @throws XbbException
     */
    private void onlyLeftExternalContact(DecisionTreeEntity entity, List<Long> contactIds, String platform, XbbRefTypeEnum xbbRefTypeEnum) throws XbbException {
        if (XbbRefTypeEnum.SALES_OPPORTUNITY != xbbRefTypeEnum) {
            return;
        }
        if (!Objects.equals(PlatFormEnum.WEB.getValue(), platform)) {
            return;
        }

        List<Long> dbLeftExternalContactIds = Objects.nonNull(entity.getLeftExternalContactIds()) ? entity.getLeftExternalContactIds().toJavaList(Long.class) : new ArrayList<>();
        contactIds = Objects.isNull(contactIds) ? new ArrayList<>() : contactIds;
        dbLeftExternalContactIds.removeIf(Objects::isNull);
        contactIds.removeIf(Objects::isNull);
        if (CollectionsUtil.isEmpty(dbLeftExternalContactIds) && CollectionsUtil.isEmpty(contactIds)) {
            return;
        }

        if (CollectionsUtil.isNotEmpty(dbLeftExternalContactIds)) {
            dbLeftExternalContactIds.removeAll(contactIds);
            if (CollectionsUtil.isEmpty(dbLeftExternalContactIds)) {
                return;
            }
        }
        JSONArray leftExternalContactData = new JSONArray();
        leftExternalContactData.addAll(contactIds);
        entity.setLeftExternalContactIds(leftExternalContactData);
        // 必填值
        JSONObject nodeData = Objects.nonNull(entity.getNodeData()) ? entity.getNodeData() : new JSONObject();
        JSONArray contactData = Objects.nonNull(entity.getContactIds()) ? entity.getContactIds() : new JSONArray();
        JSONArray externalContactData = Objects.nonNull(entity.getExternalContactIds()) ? entity.getExternalContactIds() : new JSONArray();
        entity.setNodeData(nodeData);
        entity.setContactIds(contactData);
        entity.setExternalContactIds(externalContactData);

        try {
            decisionTreeModel.save(entity);
        } catch (XbbException e) {
            LOG.error("保存决策树失败~~~", e);
            throw e;
        }
    }

}
